home *** CD-ROM | disk | FTP | other *** search
Wrap
(********************************************************************* * DSPack 2.3 * * * * home page : http://www.progdigy.com * * email : hgourvest@progdigy.com * * Thanks to Michael Andersen. (DSVideoWindowEx) * * * * date : 21-02-2003 * * * * The contents of this file are used with permission, subject to * * the Mozilla Public License Version 1.1 (the "License"); you may * * not use this file except in compliance with the License. You may * * obtain a copy of the License at * * http://www.mozilla.org/MPL/MPL-1.1.html * * * * Software distributed under the License is distributed on an * * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * * implied. See the License for the specific language governing * * rights and limitations under the License. * * * *********************************************************************) { @abstract(Methods & usefull Class for Direct Show programming.) @author(Henri Gourvest: hgourvest@progdigy.com) @created(Mar 14, 2002) @lastmod(Feb 21, 2002) } unit DSUtil; {$IFDEF VER150} {$WARN UNSAFE_CODE OFF} {$WARN UNSAFE_TYPE OFF} {$WARN UNSAFE_CAST OFF} {$ENDIF} interface uses {$IFDEF VER140} Variants, {$ENDIF} {$IFDEF VER150} Variants, {$ENDIF} Windows, Controls, SysUtils, ActiveX, Classes, MMSystem, DirectShow9; const IID_IPropertyBag : TGUID = '{55272A00-42CB-11CE-8135-00AA004BB851}'; IID_ISpecifyPropertyPages : TGUID = '{B196B28B-BAB4-101A-B69C-00AA00341D07}'; IID_IPersistStream : TGUID = '{00000109-0000-0000-C000-000000000046}'; IID_IMoniker : TGUID = '{0000000F-0000-0000-C000-000000000046}'; // MS Mepg4 DMO MEDIASUBTYPE_MP42 : TGUID = '{3234504D-0000-0010-8000-00AA00389B71}'; // DIVX MEDIASUBTYPE_DIVX : TGUID = '{58564944-0000-0010-8000-00AA00389B71}'; // VoxWare MetaSound MEDIASUBTYPE_VOXWARE : TGUID = '{00000075-0000-0010-8000-00AA00389B71}'; MiliSecPerDay : Cardinal = 86400000; MAX_TIME : Int64 = $7FFFFFFFFFFFFFFF; //////////////////////////////////////////////////////////////////////////////// // DIVX ressources translated from latest OpenDivx DirectX Codec // divx CLSID_DIVX : TGUID = '{78766964-0000-0010-8000-00aa00389b71}'; // DIVX CLSID_DivX_U : TGUID = '{58564944-0000-0010-8000-00aa00389b71}'; // dvx1 CLSID_DivX_ : TGUID = '{31787664-0000-0010-8000-00aa00389b71}'; // DVX1 CLSID_DivX__U : TGUID = '{31585644-0000-0010-8000-00aa00389b71}'; // dx50 CLSID_dx50 : TGUID = '{30357864-0000-0010-8000-00aa00389b71}'; // DX50 CLSID_DX50_ : TGUID = '{30355844-0000-0010-8000-00aa00389b71}'; // div6 CLSID_div6 : TGUID = '{36766964-0000-0010-8000-00aa00389b71}'; // DIV6 CLSID_DIV6_ : TGUID = '{36564944-0000-0010-8000-00aa00389b71}'; // div5 CLSID_div5 : TGUID = '{35766964-0000-0010-8000-00aa00389b71}'; // DIV5 CLSID_DIV5_ : TGUID = '{35564944-0000-0010-8000-00aa00389b71}'; // div4 CLSID_div4 : TGUID = '{34766964-0000-0010-8000-00aa00389b71}'; // DIV4 CLSID_DIV4_ : TGUID = '{34564944-0000-0010-8000-00aa00389b71}'; // div3 CLSID_div3 : TGUID = '{33766964-0000-0010-8000-00aa00389b71}'; // DIV3 CLSID_DIV3_ : TGUID = '{33564944-0000-0010-8000-00aa00389b71}'; CLSID_DIVXCodec : TGUID = '{78766964-0000-0010-8000-00aa00389b71}'; IID_IIDivXFilterInterface : TGUID = '{D132EE97-3E38-4030-8B17-59163B30A1F5}'; CLSID_DivXPropertiesPage : TGUID = '{310e42a0-f913-11d4-887c-006008dc5c26}'; type { Interface to control the Divx Decoder filter. TODO: discover the last function ... } IDivXFilterInterface = interface(IUnknown) ['{D132EE97-3E38-4030-8B17-59163B30A1F5}'] { OpenDivx } // current postprocessing level 0..100 function get_PPLevel(out PPLevel: integer): HRESULT; stdcall; // new postprocessing level 0..100 function put_PPLevel(PPLevel: integer): HRESULT; stdcall; // Put the default postprocessing = 0 function put_DefaultPPLevel: HRESULT; stdcall; { DIVX } function put_MaxDelayAllowed(maxdelayallowed: integer): HRESULT; stdcall; function put_Brightness(brightness: integer): HRESULT; stdcall; function put_Contrast(contrast: integer): HRESULT; stdcall; function put_Saturation(saturation: integer): HRESULT; stdcall; function get_MaxDelayAllowed(out maxdelayallowed: integer): HRESULT; stdcall; function get_Brightness(out brightness: integer): HRESULT; stdcall; function get_Contrast(out contrast: integer): HRESULT; stdcall; function get_Saturation(out saturation: integer): HRESULT; stdcall; function put_AspectRatio(x, y: integer): HRESULT; stdcall; function get_AspectRatio(out x, y: integer): HRESULT; stdcall; end; //////////////////////////////////////////////////////////////////////////////// // Ogg Vorbis type TVORBISFORMAT = record nChannels: WORD; nSamplesPerSec: Longword; nMinBitsPerSec: Longword; nAvgBitsPerSec: Longword; nMaxBitsPerSec: Longword; fQuality: Double; end; const // f07e245f-5a1f-4d1e-8bff-dc31d84a55ab CLSID_OggSplitter: TGUID = '{f07e245f-5a1f-4d1e-8bff-dc31d84a55ab}'; // {078C3DAA-9E58-4d42-9E1C-7C8EE79539C5} CLSID_OggSplitPropPage: TGUID = '{078C3DAA-9E58-4d42-9E1C-7C8EE79539C5}'; // 8cae96b7-85b1-4605-b23c-17ff5262b296 CLSID_OggMux: TGUID = '{8cae96b7-85b1-4605-b23c-17ff5262b296}'; // {AB97AFC3-D08E-4e2d-98E0-AEE6D4634BA4} CLSID_OggMuxPropPage: TGUID = '{AB97AFC3-D08E-4e2d-98E0-AEE6D4634BA4}'; // {889EF574-0656-4B52-9091-072E52BB1B80} CLSID_VorbisEnc: TGUID = '{889EF574-0656-4B52-9091-072E52BB1B80}'; // {c5379125-fd36-4277-a7cd-fab469ef3a2f} CLSID_VorbisEncPropPage: TGUID = '{c5379125-fd36-4277-a7cd-fab469ef3a2f}'; // 02391f44-2767-4e6a-a484-9b47b506f3a4 CLSID_VorbisDec: TGUID = '{02391f44-2767-4e6a-a484-9b47b506f3a4}'; // 77983549-ffda-4a88-b48f-b924e8d1f01c CLSID_OggDSAboutPage: TGUID = '{77983549-ffda-4a88-b48f-b924e8d1f01c}'; // {D2855FA9-61A7-4db0-B979-71F297C17A04} MEDIASUBTYPE_Ogg: TGUID = '{D2855FA9-61A7-4db0-B979-71F297C17A04}'; // cddca2d5-6d75-4f98-840e-737bedd5c63b MEDIASUBTYPE_Vorbis: TGUID = '{cddca2d5-6d75-4f98-840e-737bedd5c63b}'; // 6bddfa7e-9f22-46a9-ab5e-884eff294d9f FORMAT_VorbisFormat: TGUID = '{6bddfa7e-9f22-46a9-ab5e-884eff294d9f}'; //////////////////////////////////////////////////////////////////////////////// // WMF9 Utils type TWMPofiles8 = ( wmp_V80_255VideoPDA, wmp_V80_150VideoPDA, wmp_V80_28856VideoMBR, wmp_V80_100768VideoMBR, wmp_V80_288100VideoMBR, wmp_V80_288Video, wmp_V80_56Video, wmp_V80_100Video, wmp_V80_256Video, wmp_V80_384Video, wmp_V80_768Video, wmp_V80_700NTSCVideo, wmp_V80_1400NTSCVideo, wmp_V80_384PALVideo, wmp_V80_700PALVideo, wmp_V80_288MonoAudio, wmp_V80_288StereoAudio, wmp_V80_32StereoAudio, wmp_V80_48StereoAudio, wmp_V80_64StereoAudio, wmp_V80_96StereoAudio, wmp_V80_128StereoAudio, wmp_V80_288VideoOnly, wmp_V80_56VideoOnly, wmp_V80_FAIRVBRVideo, wmp_V80_HIGHVBRVideo, wmp_V80_BESTVBRVideo ); const WMProfiles8 : array[TWMPofiles8] of TGUID = ('{FEEDBCDF-3FAC-4c93-AC0D-47941EC72C0B}', '{AEE16DFA-2C14-4a2f-AD3F-A3034031784F}', '{D66920C4-C21F-4ec8-A0B4-95CF2BD57FC4}', '{5BDB5A0E-979E-47d3-9596-73B386392A55}', '{D8722C69-2419-4b36-B4E0-6E17B60564E5}', '{3DF678D9-1352-4186-BBF8-74F0C19B6AE2}', '{254E8A96-2612-405c-8039-F0BF725CED7D}', '{A2E300B4-C2D4-4fc0-B5DD-ECBD948DC0DF}', '{BBC75500-33D2-4466-B86B-122B201CC9AE}', '{29B00C2B-09A9-48bd-AD09-CDAE117D1DA7}', '{74D01102-E71A-4820-8F0D-13D2EC1E4872}', '{C8C2985F-E5D9-4538-9E23-9B21BF78F745}', '{931D1BEE-617A-4bcd-9905-CCD0786683EE}', '{9227C692-AE62-4f72-A7EA-736062D0E21E}', '{EC298949-639B-45e2-96FD-4AB32D5919C2}', '{7EA3126D-E1BA-4716-89AF-F65CEE0C0C67}', '{7E4CAB5C-35DC-45bb-A7C0-19B28070D0CC}', '{60907F9F-B352-47e5-B210-0EF1F47E9F9D}', '{5EE06BE5-492B-480a-8A8F-12F373ECF9D4}', '{09BB5BC4-3176-457f-8DD6-3CD919123E2D}', '{1FC81930-61F2-436f-9D33-349F2A1C0F10}', '{407B9450-8BDC-4ee5-88B8-6F527BD941F2}', '{8C45B4C7-4AEB-4f78-A5EC-88420B9DADEF}', '{6E2A6955-81DF-4943-BA50-68A986A708F6}', '{3510A862-5850-4886-835F-D78EC6A64042}', '{0F10D9D3-3B04-4fb0-A3D3-88D4AC854ACC}', '{048439BA-309C-440e-9CB4-3DCCA3756423}'); function ProfileFromGUID(const GUID: TGUID): TWMPofiles8; //////////////////////////////////////////////////////////////////////////////// { Frees an object reference and replaces the reference with Nil. (Delphi4 compatibility)} procedure FreeAndNil(var Obj); { Enable Graphedit to connect with a filter graph.<br> The application must register the filter graph instance in the Running Object Table (ROT). The ROT is a globally accessible look-up table that keeps track of running objects. Objects are registered in the ROT by moniker. To connect to the graph, GraphEdit searches the ROT for monikers whose display name matches a particular format: !FilterGraph X pid Y.<br> <b>Graph:</b> a graph interface (IGraphBuilder, IFilterGraph, IFilterGraph2).<br> <b>ID:</b> return the ROT identifier.} function AddGraphToRot(Graph: IFilterGraph; out ID: integer): HRESULT; { Disable Graphedit to connect with your filter graph.<br> <b>ID:</b> identifier provided by the @link(AddGraphToRot) method.} function RemoveGraphFromRot(ID: integer): HRESULT; { deprecated, convert a Time code event to TDVD_TimeCode record. } function IntToTimeCode(x : longint): TDVDTimeCode; { Return a string explaining a filter graph event. } function GetEventCodeDef(code: longint): string; { General purpose function to delete a heap allocated TAM_MEDIA_TYPE structure which is useful when calling IEnumMediaTypes.Next as the interface implementation allocates the structures which you must later delete the format block may also be a pointer to an interface to release. } procedure DeleteMediaType(pmt: PAMMediaType); { The CreateMediaType function allocates a new AM_MEDIA_TYPE structure, including the format block. This also comes in useful when using the IEnumMediaTypes interface so that you can copy a media type, you can do nearly the same by creating a TMediaType class but as soon as it goes out of scope the destructor will delete the memory it allocated (this takes a copy of the memory). } function CreateMediaType(pSrc: PAMMediaType): PAMMediaType; { The CopyMediaType function copies an AM_MEDIA_TYPE structure into another structure, including the format block. This function allocates the memory for the format block. If the pmtTarget parameter already contains an allocated format block, a memory leak will occur. To avoid a memory leak, call FreeMediaType before calling this function. } procedure CopyMediaType(pmtTarget: PAMMediaType; pmtSource: PAMMediaType); { The FreeMediaType function frees the format block in an AM_MEDIA_TYPE structure. Use this function to free just the format block. To delete the AM_MEDIA_TYPE structure, call DeleteMediaType. } procedure FreeMediaType(mt: PAMMediaType); { The CreateAudioMediaType function initializes a media type from a TWAVEFORMATEX structure. If the bSetFormat parameter is TRUE, the method allocates the memory for the format block. If the pmt parameter already contains an allocated format block, a memory leak will occur. To avoid a memory leak, call FreeMediaType before calling this function. After the method returns, call FreeMediaType again to free the format block. } function CreateAudioMediaType(pwfx: PWaveFormatEx; pmt: PAMMediaType; bSetFormat: boolean): HRESULT; { The FOURCCMap function provides conversion between GUID media subtypes and old-style FOURCC 32-bit media tags. In the original Microsoft« Windows« multimedia APIs, media types were tagged with 32-bit values created from four 8-bit characters and were known as FOURCCs. Microsoft DirectShow« media types have GUIDs for the subtype, partly because these are simpler to create (creation of a new FOURCC requires its registration with Microsoft). Because FOURCCs are unique, a one-to-one mapping has been made possible by allocating a range of 4,000 million GUIDs representing FOURCCs. This range is all GUIDs of the form: XXXXXXXX-0000-0010-8000-00AA00389B71. } function FOURCCMap(Fourcc: Cardinal): TGUID; { Find the four-character codes wich identifi a codec. } function GetFOURCC(Fourcc: Cardinal): string; { Convert a FCC (Four Char Codes) to Cardinal. A FCC identifie a media type.} function FCC(str: String): Cardinal; { Create the four-character codes from a Cardinal value. } function MAKEFOURCC(ch0, ch1, ch2, ch3: char): Cardinal; { The GetErrorString function retrieves the error message for a given return code, using the current language setting.} function GetErrorString(hr: HRESULT): string; { This function examine a media type and return a short description like GraphEdit. } function GetMediaTypeDescription(MediaType: TAMMediaType): string; { Retrieve the Size needed to store a bitmat } function GetBitmapSize(const pHeader: TBITMAPINFOHEADER): DWORD; type { Property pages.<br>See also: @link(ShowFilterPropertyPage), @link:(HaveFilterPropertyPage).} TPropertyPage = ( ppDefault, // Simple property page. ppVFWCapDisplay, // Capture Video source dialog box. ppVFWCapFormat, // Capture Video format dialog box. ppVFWCapSource, // Capture Video source dialog box. ppVFWCompConfig, // Compress Configure dialog box. ppVFWCompAbout // Compress About Dialog box. ); { Show the property page associated with the Filter. A property page is one way for a filter to support properties that the user can set. Many of the filters provided with DirectShow support property pages, they are intended for debugging purposes, and are not recommended for application use. In most cases the equivalent functionality is provided through a custom interface on the filter. An application should control these filters programatically, rather than expose their property pages to users. } function ShowFilterPropertyPage(parent: THandle; Filter: IBaseFilter; PropertyPage: TPropertyPage = ppDefault): HRESULT; { Return true if the specified property page is provided by the Filter.} function HaveFilterPropertyPage(Filter: IBaseFilter; PropertyPage: TPropertyPage = ppDefault): boolean; { Show the property page associated with the Pin. <br> <b>See also: </b> @link:(ShowFilterPropertyPage).} function ShowPinPropertyPage(parent: THandle; Pin: IPin): HRESULT; { Convert 100 nano sec unit to milisecondes. } function RefTimeToMiliSec(RefTime: Int64): Cardinal; { Convert milisecondes to 100 nano sec unit} function MiliSecToRefTime(Milisec: int64): Int64; { The mechanism for describing a bitmap format is with the BITMAPINFOHEADER This is really messy to deal with because it invariably has fields that follow it holding bit fields, palettes and the rest. This function gives the number of bytes required to hold a VIDEOINFO that represents it. This count includes the prefix information (like the rcSource rectangle) the BITMAPINFOHEADER field, and any other colour information on the end. WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't right at the start of the VIDEOINFO (there are a number of other fields), CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); } function GetBitmapFormatSize(const Header: TBitmapInfoHeader): Integer; { Retrieve original source rectangle from a TAM_Media_type record.} function GetSourceRectFromMediaType(const MediaType: TAMMediaType): TRect; { TODO -oMichael Andersen: make documentation } function StretchRect(R, IR: TRect): TRect; // raise @link(EDirectShowException) exception if failed. function CheckDSError(HR: HRESULT): HRESULT; type // DirectShow Exception class EDirectShowException = class(Exception) ErrorCode: Integer; end; EDSPackException = class(Exception) ErrorCode: Integer; end; // ***************************************************************************** // TSysDevEnum // ***************************************************************************** {@exclude} PFilCatNode = ^TFilCatNode; {@exclude} TFilCatNode = record FriendlyName : Shortstring; CLSID : TGUID; end; { Usefull class to enumerate availables filters. See "Filter Enumerator" sample. } TSysDevEnum = class private FGUID : TGUID; FCategories : TList; FFilters : TList; ACategory : PFilCatNode; procedure GetCat(catlist: TList; CatGUID: TGUID); function GetCountCategories: integer; function GetCountFilters: integer; function GetCategory(item: integer): TFilCatNode; function GetFilter(item: integer): TFilCatNode; public { Select the main category by GUID. For example CLSID_VideoCompressorCategory to enumerate Video Compressors. } procedure SelectGUIDCategory(GUID: TGUID); { Select the main category by Index. } procedure SelectIndexCategory(index: integer); { Call CountCategories to retrieve categories count.} property CountCategories: integer read GetCountCategories; { Call CountFilters to retrieve the number of Filte within a Category. } property CountFilters: integer read GetCountFilters; { Call Categories to read Category Name and GUID. } property Categories[item: integer]: TFilCatNode read GetCategory; { Call Filters to read Filter Name and GUID. } property Filters[item: integer]: TFilCatNode read GetFilter; { Call GetBaseFilter to retrieve the IBaseFilter interface corresponding to index. } function GetBaseFilter(index: integer): IBaseFilter; overload; { Call GetBaseFilter to retrieve the IBaseFilter interface corresponding to GUID. } function GetBaseFilter(GUID: TGUID): IBaseFilter; overload; { Call GetMoniker to retrieve the IMoniker interface corresponding to index. This interface can be used to store a filter with the @link(TBaseFiter) class. } function GetMoniker(index: integer): IMoniker; { constructor } Constructor Create; overload; { constructor. Create the class and initialize the main category with the GUID. } constructor Create(guid: TGUID); overload; { destructor } destructor Destroy; override; end; // ***************************************************************************** // TFilterList // ***************************************************************************** { This class can enumerate all filters in a FilterGraph. } TFilterList = class(TInterfaceList) private Graph : IFilterGraph; function GetFilter(Index: Integer): IBaseFilter; procedure PutFilter(Index: Integer; Item: IBaseFilter); function GetFilterInfo(index: integer): TFilterInfo; public { Create a list based on a FilterGraph. } constructor Create(FilterGraph: IFilterGraph); overload; { Destructor. } destructor Destroy; override; { Update the list. } procedure Update; { Reload the list from another FilterGraph.} procedure Assign(FilterGraph: IFilterGraph); { Call First to obtain the first interface in the list. } function First: IBaseFilter; { Call IndexOf to obtain the index of an interface. } function IndexOf(Item: IBaseFilter): Integer; { Call Add to add an interface to the list. } function Add(Item: IBaseFilter): Integer; { Call Insert to insert an interface into the list. Item is the interface to insert, and Index indicates the position (zero-offset) where the interface should be added. } procedure Insert(Index: Integer; Item: IBaseFilter); { Call Last to obtain the last interface in the list. } function Last: IBaseFilter; { Call Remove to remove an interface from the list. Remove returns the index of the removed interface, or û1 if the interface was not found. } function Remove(Item: IBaseFilter): Integer; { Use Items to directly access an interface in the list. Index identifies each interface by its position in the list. } property Items[Index: Integer]: IBaseFilter read GetFilter write PutFilter; default; { call FilterInfo to retrieve the Filer name and his FilterGraph. } property FilterInfo[Index: Integer] : TFilterInfo read GetFilterInfo; end; //****************************************************************************** // TPinList //****************************************************************************** {Helper class to enumerate pins on a filter. } TPinList = class(TInterfaceList) private Filter: IBaseFilter; function GetPin(Index: Integer): IPin; procedure PutPin(Index: Integer; Item: IPin); function GetPinInfo(index: integer): TPinInfo; function GetConnected(Index: Integer): boolean; public { Create a Pin list from the IBaseFilter interface. } constructor Create(BaseFilter: IBaseFilter); overload; { Destructor. } destructor Destroy; override; { Update the Pin list. } procedure Update; { Load a Pin list from the IBaseFilter Interface. } procedure Assign(BaseFilter: IBaseFilter); { Return the First Pin from in the list. } function First: IPin; { Return the index of Pin in the list. } function IndexOf(Item: IPin): Integer; { Add A Pin to the list. } function Add(Item: IPin): Integer; { Insert a pin at the given position. } procedure Insert(Index: Integer; Item: IPin); { Return the last pin in the list. } function Last: IPin; { Remove a pin from the lis. } function Remove(Item: IPin): Integer; { Return the the pin interface at the defined position. } property Items[Index: Integer]: IPin read GetPin write PutPin; default; { Retrieve informations on a pin. } property PinInfo[Index: Integer]: TPinInfo read GetPinInfo; property Connected[Index: Integer]: boolean read GetConnected; end; // ***************************************************************************** // TMediaType // ***************************************************************************** { Uses TMediaType to configure media types. This class have a special property editor. See @link(TSampleGrabber)} TMediaType = class(TPersistent) private function GetMajorType: TGUID; procedure SetMajorType(MT: TGUID); function GetSubType: TGUID; procedure SetSubType(ST: TGUID); procedure SetFormatType(const GUID: TGUID); function GetFormatType: TGUID; procedure ReadData(Stream: TStream); procedure WriteData(Stream: TStream); protected { @exclude} procedure DefineProperties(Filer: TFiler); override; public { Local copy of the Media Type. } AMMediaType: PAMMediaType; { Destructor method. } destructor Destroy; override; { Constructor method. } constructor Create; overload; { Constructor method. Initialised with majortype. } constructor Create(majortype: TGUID); overload; { Constructor method. Initialised with another media type. } constructor Create(mediatype: PAMMediaType); overload; { Constructor method. Initialised with another TMediaType} constructor Create(MTClass: TMediaType); overload; { Copy from another TMediaType. } procedure Assign(Source: TPersistent); override; { Copy from another PAM_MEDIA_TYPE. } procedure Read(mediatype: PAMMediaType); { Tests for equality between TMediaType objects.<br> <b>rt:</b> Reference to the TMediaType object to compare.<br> Returns TRUE if rt is equal to this object. Otherwise, returns FALSE. } function Equal(MTClass: TMediaType): boolean; overload; { Tests for inequality between TMediaType objects.<br> <b>rt:</b> Reference to the TMediaType object to compare.<br> Returns TRUE if rt is not equal to this object. Otherwise, returns FALSE. } function NotEqual(MTClass: TMediaType): boolean; overload; { The IsValid method determines whether a major type has been assigned to this object. Returns TRUE if a major type has been assigned to this object. Otherwise, returns FALSE. By default, TMediaType objects are initialized with a major type of GUID_NULL. Call this method to determine whether the object has been correctly initialized.} function IsValid: boolean; { The IsFixedSize method determines if the samples have a fixed size or a variable size. Returns the value of the bFixedSizeSamples member.} function IsFixedSize: boolean; { The IsTemporalCompressed method determines if the stream uses temporal compression. Returns the value of the bTemporalCompression member. } function IsTemporalCompressed: boolean; { The GetSampleSize method retrieves the sample size. If the sample size is fixed, returns the sample size in bytes. Otherwise, returns zero. } function GetSampleSize: ULONG; { The SetSampleSize method specifies a fixed sample size, or specifies that samples have a variable size. If value of sz is zero, the media type uses variable sample sizes. Otherwise, the sample size is fixed at sz bytes. } procedure SetSampleSize(SZ: ULONG); { The SetVariableSize method specifies that samples do not have a fixed size. This method sets the bFixedSizeSamples member to FALSE. Subsequent calls to the TMediaType.GetSampleSize method return zero. } procedure SetVariableSize; { The SetTemporalCompression method specifies whether samples are compressed using temporal (interframe) compression. } procedure SetTemporalCompression(bCompressed: boolean); { read/write pointer to format - can't change length without calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer} function Format: pointer; { The FormatLength method retrieves the length of the format block. } function FormatLength: ULONG; { The SetFormat method specifies the format block.<br> <b>pFormat:</b> Pointer to a block of memory that contains the format block.<br> <b>length:</b> Length of the format block, in bytes. } function SetFormat(pFormat: pointer; length: ULONG): boolean; { The ResetFormatBuffer method deletes the format block. } procedure ResetFormatBuffer; { The AllocFormatBuffer method allocates memory for the format block.<br> <b>length:</b> Size required for the format block, in bytes.<br> Returns a pointer to the new block if successful. Otherwise, returns nil.<br> If the method successfully allocates a new format block, it frees the existing format block. If the allocation fails, the method leaves the existing format block. } function AllocFormatBuffer(length: ULONG): pointer; { The ReallocFormatBuffer method reallocates the format block to a new size.<br> <b>length:</b> New size required for the format block, in bytes. Must be greater than zero.<br> Returns a pointer to the new block if successful. Otherwise, returns either a pointer to the old format block, or nil. This method allocates a new format block. It copies as much of the existing format block as possible into the new format block. If the new block is smaller than the existing block, the existing format block is truncated. If the new block is larger, the contents of the additional space are undefined. They are not explicitly set to zero. } function ReallocFormatBuffer(length: ULONG): pointer; { The InitMediaType method initializes the media type. This method zeroes the object's memory, sets the fixed-sample-size property to TRUE, and sets the sample size to 1. } procedure InitMediaType; { The MatchesPartial method determines if this media type matches a partially specified media type. The media type specified by ppartial can have a value of GUID_NULL for the major type, subtype, or format type. Any members with GUID_NULL values are not tested. (In effect, GUID_NULL acts as a wildcard.) Members with values other than GUID_NULL must match for the media type to match.} function MatchesPartial(ppartial: TMediaType): boolean; { The IsPartiallySpecified method determines if the media type is partially defined. A media type is partial if the major type, subtype, or format type is GUID_NULL. The IPin.Connect method can accept partial media types. The implementation does not actually test the subtype. If there is a specified format type, the media type is not considered partial, even if the subtype is GUID_NULL. } function IsPartiallySpecified: boolean; { Set or retrieve the MajorType GUID. } property MajorType: TGUID read GetMajorType write SetMajorType; { Set or retrieve the SubType GUID. } property SubType: TGUID read GetSubType write SetSubType; { Set or retrieve the FormatType GUID. } property FormatType: TGUID read GetFormatType write SetFormatType; end; // ***************************************************************************** // TEnumMediaType // ***************************************************************************** { This class can retrieve all media types from a pin, a file or an IEnumMediaTypes interface. } TEnumMediaType = class(TObject) private FList : TList; function GetItem(Index: Integer): TMediaType; procedure SetItem(Index: Integer; Item: TMediaType); function GetMediaDescription(Index: Integer): string; function GetCount: integer; public { Constructor method.} constructor Create; overload; { Constructor method enumerating all media types on a pin. } constructor Create(Pin: IPin); overload; { Constructor method enumerating media types provided by a IEnumMediaType interface. } constructor Create(EnumMT: IEnumMediaTypes); overload; { Constructor method enumerating all media types availables in a media file. Support WMF files. } constructor Create(FileName: TFileName); overload; { Destructor method. } destructor Destroy; override; { Enumerate all media types on a pin.} procedure Assign(Pin: IPin); overload; { Enumerate media types provided by a IEnumMediaType interface. } procedure Assign(EnumMT: IEnumMediaTypes); overload; { Enumerate all media types availables in a media file. Support WMF files. } procedure Assign(FileName: TFileName); overload; { Add a media type to the list. } function Add(Item: TMediaType): Integer; { Clear the list. } procedure Clear; { Remove a media type from the list. } procedure Delete(Index: Integer); { Retrieve a mediaa type. } property Items[Index: Integer]: TMediaType read GetItem write SetItem; { Return a string describing the media type. } property MediaDescription[Index: Integer]: string read GetMediaDescription; { Number of items in the list. } property Count: integer read GetCount; end; // ***************************************************************************** // TPersistentMemory // ***************************************************************************** { For internal use. This class is designed to store a custom memory stream with a form. It is the ancestor of @link(TBaseFilter).} TPersistentMemory = class(TPersistent) private FData: pointer; FDataLength: Cardinal; procedure ReadData(Stream: TStream); procedure WriteData(Stream: TStream); function Equal(Memory: TPersistentMemory): boolean; procedure AllocateMemory(ALength: Cardinal); protected { @exclude } procedure AssignTo(Dest: TPersistent); override; { @exclude } procedure DefineProperties(Filer: TFiler); override; public { Set/Get the buffer length. } property DataLength: Cardinal read FDataLength write AllocateMemory; { Pointer to buffer. } property Data: Pointer read FData; { Constructor } constructor Create; virtual; { Destructor } destructor Destroy; override; { Call Assign to copy the properties or other attributes of one object from another. } procedure Assign(Source: TPersistent); override; end; // ***************************************************************************** // TBaseFilter // ***************************************************************************** { This class can store a custom filter as a moniker within the dfm file. } TBaseFilter = class(TPersistentMemory) private procedure SetMoniker(Moniker: IMoniker); function GetMoniker: IMoniker; public { Set or retrieve the moniker interface.} property Moniker: IMoniker read GetMoniker write SetMoniker; { Read a property bag. For example you can read the GUID identifier (PropertyBag('CLSID'))} function PropertyBag(Name: WideString): OleVariant; {Return the IBaseFilter interface corresponding to filter.} function CreateFilter: IBaseFilter; end; {$IFDEF VER130} procedure Set8087CW(NewCW: Word); function Get8087CW: Word; {$ENDIF} implementation uses DirectSound, math, ComObj; {$IFDEF VER130} var Default8087CW: Word = $1372; procedure Set8087CW(NewCW: Word); begin Default8087CW := NewCW; asm FNCLEX FLDCW Default8087CW end; end; function Get8087CW: Word; asm PUSH 0 FNSTCW [ESP].Word POP EAX end; {$ENDIF} function ProfileFromGUID(const GUID: TGUID): TWMPofiles8; begin for result := low(TWMPofiles8) to high(TWMPofiles8) do if IsEqualGUID(GUID, WMProfiles8[result]) then Exit; Result := TWMPofiles8(-1); end; //---------------------------------------------------------------------------- // Retrieve the Size needed to store a bitmat //---------------------------------------------------------------------------- function GetBitmapSize(const pHeader: TBITMAPINFOHEADER): DWORD; function WIDTHBYTES(bits: DWORD): DWORD; begin result := DWORD((bits+31) and (not 31)) div 8; end; function DIBWIDTHBYTES(bi: TBITMAPINFOHEADER): DWORD; begin result := DWORD(WIDTHBYTES(DWORD(bi.biWidth) * DWORD(bi.biBitCount))); end; function _DIBSIZE(bi: TBITMAPINFOHEADER): DWORD; begin result := DIBWIDTHBYTES(bi) * DWORD(bi.biHeight); end; begin if (pHeader.biHeight < 0) then result := -1 * _DIBSIZE(pHeader) else result := _DIBSIZE(pHeader); end; //---------------------------------------------------------------------------- // Frees an object reference and replaces the reference with Nil. //---------------------------------------------------------------------------- procedure FreeAndNil(var Obj); var Temp: TObject; begin Temp := TObject(Obj); Pointer(Obj) := nil; Temp.Free; end; //---------------------------------------------------------------------------- // Enable Graphedit to connect with your filter graph //---------------------------------------------------------------------------- function AddGraphToRot(Graph: IFilterGraph; out ID: integer): HRESULT; var Moniker: IMoniker; ROT : IRunningObjectTable; wsz : WideString; begin result := GetRunningObjectTable(0, ROT); if (result <> S_OK) then exit; wsz := format('FilterGraph %p pid %x',[pointer(graph),GetCurrentProcessId()]); result := CreateItemMoniker('!', PWideChar(wsz), Moniker); if (result <> S_OK) then exit; result := ROT.Register(0, Graph, Moniker, ID); Moniker := nil; end; //---------------------------------------------------------------------------- // Disable Graphedit to connect with your filter graph //---------------------------------------------------------------------------- function RemoveGraphFromRot(ID: integer): HRESULT; var ROT: IRunningObjectTable; begin result := GetRunningObjectTable(0, ROT); if (result <> S_OK) then exit; result := ROT.Revoke(ID); ROT := nil; end; function IntToTimeCode(x : longint): TDVDTimeCode; begin Result.Hours1 := (x and $F0000000) shr 28; Result.Hours10 := (x and $0F000000) shr 24; Result.Minutes1 := (x and $00F00000) shr 20; Result.Minutes10 := (x and $000F0000) shr 16; Result.Seconds1 := (x and $0000F000) shr 12; Result.Seconds10 := (x and $00000F00) shr 08; Result.Frames1 := (x and $000000F0) shr 04; Result.Frames10 := (x and $0000000C) shr 02; Result.FrameRateCode := (x and $00000003) shr 00; end; function GetEventCodeDef(code: longint): string; begin case code of EC_ACTIVATE : result:= 'EC_ACTIVATE - A video window is being activated or deactivated.'; EC_BUFFERING_DATA : result:= 'EC_BUFFERING_DATA - The graph is buffering data, or has stopped buffering data.'; EC_CLOCK_CHANGED : result:= 'EC_CLOCK_CHANGED - The reference clock has changed.'; EC_COMPLETE : result:= 'EC_COMPLETE - All data from a particular stream has been rendered.'; EC_DEVICE_LOST : result:= 'EC_DEVICE_LOST - A Plug and Play device was removed or has become available again.'; EC_DISPLAY_CHANGED : result:= 'EC_DISPLAY_CHANGED - The display mode has changed.'; EC_END_OF_SEGMENT : result:= 'EC_END_OF_SEGMENT - The end of a segment has been reached.'; EC_ERROR_STILLPLAYING : result:= 'EC_ERROR_STILLPLAYING - An asynchronous command to run the graph has failed.'; EC_ERRORABORT : result:= 'EC_ERRORABORT - An operation was aborted because of an error.'; EC_FULLSCREEN_LOST : result:= 'EC_FULLSCREEN_LOST - The video renderer is switching out of full-screen mode.'; EC_GRAPH_CHANGED : result:= 'EC_GRAPH_CHANGED - The filter graph has changed.'; EC_NEED_RESTART : result:= 'EC_NEED_RESTART - A filter is requesting that the graph be restarted.'; EC_NOTIFY_WINDOW : result:= 'EC_NOTIFY_WINDOW - Notifies a filter of the video renderer''s window.'; EC_OLE_EVENT : result:= 'EC_OLE_EVENT - A filter is passing a text string to the application.'; EC_OPENING_FILE : result:= 'EC_OPENING_FILE - The graph is opening a file, or has finished opening a file.'; EC_PALETTE_CHANGED : result:= 'EC_PALETTE_CHANGED - The video palette has changed.'; EC_PAUSED : result:= 'EC_PAUSED - A pause request has completed.'; EC_QUALITY_CHANGE : result:= 'EC_QUALITY_CHANGE - The graph is dropping samples, for quality control.'; EC_REPAINT : result:= 'EC_REPAINT - A video renderer requires a repaint.'; EC_SEGMENT_STARTED : result:= 'EC_SEGMENT_STARTED - A new segment has started.'; EC_SHUTTING_DOWN : result:= 'EC_SHUTTING_DOWN - The filter graph is shutting down, prior to being destroyed.'; EC_SNDDEV_IN_ERROR : result:= 'EC_SNDDEV_IN_ERROR - An audio device error has occurred on an input pin.'; EC_SNDDEV_OUT_ERROR : result:= 'EC_SNDDEV_OUT_ERROR - An audio device error has occurred on an output pin.'; EC_STARVATION : result:= 'EC_STARVATION - A filter is not receiving enough data.'; EC_STEP_COMPLETE : result:= 'EC_STEP_COMPLETE - A filter performing frame stepping has stepped the specified number of frames.'; EC_STREAM_CONTROL_STARTED : result:= 'EC_STREAM_CONTROL_STARTED - A stream-control start command has taken effect.'; EC_STREAM_CONTROL_STOPPED : result:= 'EC_STREAM_CONTROL_STOPPED - A stream-control start command has taken effect.'; EC_STREAM_ERROR_STILLPLAYING : result:= 'EC_STREAM_ERROR_STILLPLAYING - An error has occurred in a stream. The stream is still playing.'; EC_STREAM_ERROR_STOPPED : result:= 'EC_STREAM_ERROR_STOPPED - A stream has stopped because of an error.'; EC_USERABORT : result:= 'EC_USERABORT - The user has terminated playback.'; EC_VIDEO_SIZE_CHANGED : result:= 'EC_VIDEO_SIZE_CHANGED - The native video size has changed.'; EC_WINDOW_DESTROYED : result:= 'EC_WINDOW_DESTROYED - The video renderer was destroyed or removed from the graph.'; EC_TIMECODE_AVAILABLE : result:= 'EC_TIMECODE_AVAILABLE- Sent by filter supporting timecode.'; EC_EXTDEVICE_MODE_CHANGE : result:= 'EC_EXTDEVICE_MODE_CHANGE - Sent by filter supporting IAMExtDevice.'; EC_CLOCK_UNSET : result:= 'EC_CLOCK_UNSET - notify the filter graph to unset the current graph clock.'; EC_TIME : result:= 'EC_TIME - The requested reference time occurred (currently not used).'; EC_VMR_RENDERDEVICE_SET : result:= 'EC_VMR_RENDERDEVICE_SET - Identifies the type of rendering mechanism the VMR is using to display video.'; EC_DVD_ANGLE_CHANGE : result:= 'EC_DVD_ANGLE_CHANGE - Signals that either the number of available angles changed or that the current angle number changed.'; EC_DVD_ANGLES_AVAILABLE : result:= 'EC_DVD_ANGLES_AVAILABLE - Indicates whether an angle block is being played and angle changes can be performed.'; EC_DVD_AUDIO_STREAM_CHANGE : result:= 'EC_DVD_AUDIO_STREAM_CHANGE - Signals that the current audio stream number changed for the main title.'; EC_DVD_BUTTON_AUTO_ACTIVATED : result:= 'EC_DVD_BUTTON_AUTO_ACTIVATED - Signals that a menu button has been automatically activated per instructions on the disc.'; EC_DVD_BUTTON_CHANGE : result:= 'EC_DVD_BUTTON_CHANGE - Signals that either the number of available buttons changed or that the currently selected button number changed.'; EC_DVD_CHAPTER_AUTOSTOP : result:= 'EC_DVD_CHAPTER_AUTOSTOP - Indicates that playback stopped as the result of a call to the IDvdControl2::PlayChaptersAutoStop method.'; EC_DVD_CHAPTER_START : result:= 'EC_DVD_CHAPTER_START - Signals that the DVD Navigator started playback of a new chapter in the current title.'; EC_DVD_CMD_START : result:= 'EC_DVD_CMD_START - Signals that a particular command has begun.'; EC_DVD_CMD_END : result:= 'EC_DVD_CMD_END - Signals that a particular command has completed.'; EC_DVD_CURRENT_HMSF_TIME : result:= 'EC_DVD_CURRENT_HMSF_TIME - Signals the current time in DVD_HMSF_TIMECODE format at the beginning of every VOBU, which occurs every .4 to 1.0 sec.'; EC_DVD_CURRENT_TIME : result:= 'EC_DVD_CURRENT_TIME - Signals the beginning of every video object unit (VOBU), a video segment which is 0.4 to 1.0 seconds in length.'; EC_DVD_DISC_EJECTED : result:= 'EC_DVD_DISC_EJECTED - Signals that a disc has been ejected from the drive.'; EC_DVD_DISC_INSERTED : result:= 'EC_DVD_DISC_INSERTED - Signals that a disc has been inserted into the drive.'; EC_DVD_DOMAIN_CHANGE : result:= 'EC_DVD_DOMAIN_CHANGE - Indicates the DVD Navigator''s new domain.'; EC_DVD_ERROR : result:= 'EC_DVD_ERROR - Signals a DVD error condition.'; EC_DVD_KARAOKE_MODE : result:= 'EC_DVD_KARAOKE_MODE - Indicates that the Navigator has either begun playing or finished playing karaoke data.'; EC_DVD_NO_FP_PGC : result:= 'EC_DVD_NO_FP_PGC - Indicates that the DVD disc does not have a FP_PGC (First Play Program Chain).'; EC_DVD_PARENTAL_LEVEL_CHANGE : result:= 'EC_DVD_PARENTAL_LEVEL_CHANGE - Signals that the parental level of the authored content is about to change.'; EC_DVD_PLAYBACK_RATE_CHANGE : result:= 'EC_DVD_PLAYBACK_RATE_CHANGE - Indicates that a playback rate change has been initiated and the new rate is in the parameter.'; EC_DVD_PLAYBACK_STOPPED : result:= 'EC_DVD_PLAYBACK_STOPPED - Indicates that playback has been stopped. The DVD Navigator has completed playback of the title and did not find any other branching instruction for subsequent playback.'; EC_DVD_PLAYPERIOD_AUTOSTOP : result:= 'EC_DVD_PLAYPERIOD_AUTOSTOP - Indicates that the Navigator has finished playing the segment specified in a call to PlayPeriodInTitleAutoStop.'; EC_DVD_STILL_OFF : result:= 'EC_DVD_STILL_OFF - Signals the end of any still.'; EC_DVD_STILL_ON : result:= 'EC_DVD_STILL_ON - Signals the beginning of any still.'; EC_DVD_SUBPICTURE_STREAM_CHANGE : result:= 'EC_DVD_SUBPICTURE_STREAM_CHANGE - Signals that the current subpicture stream number changed for the main title.'; EC_DVD_TITLE_CHANGE : result:= 'EC_DVD_TITLE_CHANGE - Indicates when the current title number changes.'; EC_DVD_VALID_UOPS_CHANGE : result:= 'EC_DVD_VALID_UOPS_CHANGE - Signals that the available set of IDVDControl2 interface methods has changed.'; EC_DVD_WARNING : result:= 'EC_DVD_WARNING - Signals a DVD warning condition.' else result := format('Unknow Graph Event ($%x)',[code]); end; end; // general purpose function to delete a heap allocated AM_MEDIA_TYPE structure // which is useful when calling IEnumMediaTypes::Next as the interface // implementation allocates the structures which you must later delete // the format block may also be a pointer to an interface to release procedure DeleteMediaType(pmt: PAMMediaType); begin // allow nil pointers for coding simplicity if (pmt = nil) then exit; FreeMediaType(pmt); CoTaskMemFree(pmt); end; // this also comes in useful when using the IEnumMediaTypes interface so // that you can copy a media type, you can do nearly the same by creating // a CMediaType object but as soon as it goes out of scope the destructor // will delete the memory it allocated (this takes a copy of the memory) function CreateMediaType(pSrc: PAMMediaType): PAMMediaType; var pMediaType: PAMMediaType; begin ASSERT(pSrc<>nil); // Allocate a block of memory for the media type pMediaType := CoTaskMemAlloc(sizeof(TAMMediaType)); if (pMediaType = nil) then begin result := nil; exit; end; // Copy the variable length format block CopyMediaType(pMediaType,pSrc); result := pMediaType; end; //---------------------------------------------------------------------------- // Copies a task-allocated AM_MEDIA_TYPE structure. //---------------------------------------------------------------------------- procedure CopyMediaType(pmtTarget: PAMMediaType; pmtSource: PAMMediaType); begin // We'll leak if we copy onto one that already exists - there's one // case we can check like that - copying to itself. ASSERT(pmtSource <> pmtTarget); //pmtTarget^ := pmtSource^; move(pmtSource^, pmtTarget^, SizeOf(TAMMediaType)); if (pmtSource.cbFormat <> 0) then begin ASSERT(pmtSource.pbFormat <> nil); pmtTarget.pbFormat := CoTaskMemAlloc(pmtSource.cbFormat); if (pmtTarget.pbFormat = nil) then pmtTarget.cbFormat := 0 else CopyMemory(pmtTarget.pbFormat, pmtSource.pbFormat, pmtTarget.cbFormat); end; if (pmtTarget.pUnk <> nil) then pmtTarget.pUnk._AddRef; end; procedure FreeMediaType(mt: PAMMediaType); begin if (mt^.cbFormat <> 0) then begin CoTaskMemFree(mt^.pbFormat); // Strictly unnecessary but tidier mt^.cbFormat := 0; mt^.pbFormat := nil; end; if (mt^.pUnk <> nil) then mt^.pUnk := nil; end; //---------------------------------------------------------------------------- // Initializes a media type structure given a wave format structure. //---------------------------------------------------------------------------- function CreateAudioMediaType(pwfx: PWaveFormatEx; pmt: PAMMediaType; bSetFormat: boolean): HRESULT; begin pmt.majortype := MEDIATYPE_Audio; if (pwfx.wFormatTag = WAVE_FORMAT_EXTENSIBLE) then pmt.subtype := PWAVEFORMATEXTENSIBLE(pwfx).SubFormat else pmt.subtype := FOURCCMap(pwfx.wFormatTag); pmt.formattype := FORMAT_WaveFormatEx; pmt.bFixedSizeSamples := TRUE; pmt.bTemporalCompression := FALSE; pmt.lSampleSize := pwfx.nBlockAlign; pmt.pUnk := nil; if (bSetFormat) then begin if (pwfx.wFormatTag = WAVE_FORMAT_PCM) then pmt.cbFormat := sizeof(TWAVEFORMATEX) else pmt.cbFormat := sizeof(TWAVEFORMATEX) + pwfx.cbSize; pmt.pbFormat := CoTaskMemAlloc(pmt.cbFormat); if (pmt.pbFormat = nil) then begin result := E_OUTOFMEMORY; exit; end; if (pwfx.wFormatTag = WAVE_FORMAT_PCM) then begin CopyMemory(pmt.pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); PWAVEFORMATEX(pmt.pbFormat).cbSize := 0; end else begin CopyMemory(pmt.pbFormat, pwfx, pmt.cbFormat); end; end; result := S_OK; end; function FOURCCMap(Fourcc: Cardinal): TGUID; const tmpguid : TGUID = '{00000000-0000-0010-8000-00AA00389B71}'; begin result := tmpguid; result.D1 := Fourcc; end; { Convert a FCC (Four Char Codes) to Cardinal. A FCC identifie a media type.} {$NODEFINE FCC} function FCC(str: String): Cardinal; begin Assert(Length(str) >= 4); result := PDWORD(str)^; end; function GetFOURCC(Fourcc: Cardinal): string; type TFOURCC= array[0..3] of char; var CC: TFOURCC; begin case Fourcc of 0 : result := 'RGB'; 1 : result := 'RLE8'; 2 : result := 'RLE4'; 3 : result := 'BITFIELDS'; else PDWORD(@CC)^ := Fourcc; // abracadabra result := CC; end; end; {$NODEFINE MAKEFOURCC} function MAKEFOURCC(ch0, ch1, ch2, ch3: char): Cardinal; begin result := Cardinal(BYTE(ch0)) or (Cardinal(BYTE(ch1)) shl 8) or (Cardinal(BYTE(ch2)) shl 16) or (Cardinal(BYTE(ch3)) shl 24) end; function GetErrorString(hr: HRESULT): string; var buffer: array[0..254] of char; begin AMGetErrorText(hr,@buffer,255); result := buffer; end; function GetMediaTypeDescription(MediaType: TAMMediaType): string; begin // major types result := 'Major Type: '; if IsEqualGUID(MediaType.majortype,MEDIATYPE_AnalogAudio) then result := result+'AnalogAudio' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_AnalogVideo) then result := result+'Analogvideo' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Audio) then result := result+'Audio' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_AUXLine21Data) then result := result+'AUXLine21Data' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_File) then result := result+'File' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Interleaved) then result := result+'Interleaved' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_LMRT) then result := result+'LMRT' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Midi) then result := result+'Midi' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_MPEG2_PES) then result := result+'MPEG2_PES' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_ScriptCommand) then result := result+'ScriptCommand' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Stream) then result := result+'Stream' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Text) then result := result+'Text' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Timecode) then result := result+'Timecode' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_URL_STREAM) then result := result+'URL_STREAM' else if IsEqualGUID(MediaType.majortype,MEDIATYPE_Video) then result := result+'Video' else result := result+'UnKnown '; // sub types result := result + ' - Sub Type: '; if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_CLPL) then result := result+'CLPL' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_YUYV) then result := result+'YUYV' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_IYUV) then result := result+'IYUV' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_YVU9) then result := result+'YVU9' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Y411) then result := result+'Y411' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Y41P) then result := result+'Y41P' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_YUY2) then result := result+'YUY2' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_YVYU) then result := result+'YVYU' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_UYVY) then result := result+'UYVY' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Y211) then result := result+'Y211' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_YV12) then result := result+'YV12' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_CLJR) then result := result+'CLJR' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_IF09) then result := result+'IF09' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_CPLA) then result := result+'CPLA' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MJPG) then result := result+'MJPG' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_TVMJ) then result := result+'TVMJ' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_WAKE) then result := result+'WAKE' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_CFCC) then result := result+'CFCC' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_IJPG) then result := result+'IJPG' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Plum) then result := result+'Plum' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVCS) then result := result+'DVCS' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVSD) then result := result+'DVSD' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MDVF) then result := result+'MDVF' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB1) then result := result+'RGB1' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB4) then result := result+'RGB4' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB8) then result := result+'RGB8' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB565) then result := result+'RGB565' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB555) then result := result+'RGB555' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB24) then result := result+'RGB24' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RGB32) then result := result+'RGB32' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_ARGB32) then result := result+'ARGB32' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Overlay) then result := result+'Overlay' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1Packet) then result := result+'MPEG1Packet' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1Payload) then result := result+'MPEG1Payload' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1AudioPayload) then result := result+'MPEG1AudioPayload' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1System) then result := result+'MPEG1System' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1VideoCD) then result := result+'MPEG1VideoCD' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1Video) then result := result+'MPEG1Video' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG1Audio) then result := result+'MPEG1Audio' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Avi) then result := result+'Avi' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Asf) then result := result+'Asf' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_QTMovie) then result := result+'QTMovie' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_QTRpza) then result := result+'QTRpza' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_QTSmc) then result := result+'QTSmc' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_QTRle) then result := result+'QTRle' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_QTJpeg) then result := result+'QTJpeg' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_PCMAudio_Obsolete) then result := result+'PCMAudio_Obsolete' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_PCM) then result := result+'PCM' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_WAVE) then result := result+'WAVE' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AU) then result := result+'AU' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AIFF) then result := result+'AIFF' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_dvsd_) then result := result+'dvsd_' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_dvhd) then result := result+'dvhd' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_dvsl) then result := result+'dvsl' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Line21_BytePair) then result := result+'Line21_BytePair' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Line21_GOPPacket) then result := result+'Line21_GOPPacket' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_Line21_VBIRawData) then result := result+'Line21_VBIRawData' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DRM_Audio) then result := result+'DRM_Audio' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_IEEE_FLOAT) then result := result+'IEEE_FLOAT' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DOLBY_AC3_SPDIF) then result := result+'DOLBY_AC3_SPDIF' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_RAW_SPORT) then result := result+'RAW_SPORT' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_SPDIF_TAG_241h) then result := result+'SPDIF_TAG_241h' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DssVideo) then result := result+'DssVideo' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DssAudio) then result := result+'DssAudio' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_VPVideo) then result := result+'VPVideo' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_VPVBI) then result := result+'VPVBI' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_NTSC_M) then result := result+'AnalogVideo_NTSC_M' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_B) then result := result+'AnalogVideo_PAL_B' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_D) then result := result+'AnalogVideo_PAL_D' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_G) then result := result+'AnalogVideo_PAL_G' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_H) then result := result+'AnalogVideo_PAL_H' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_I) then result := result+'AnalogVideo_PAL_I' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_M) then result := result+'AnalogVideo_PAL_M' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_N) then result := result+'AnalogVideo_PAL_N' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_PAL_N_COMBO) then result := result+'AnalogVideo_PAL_N_COMBO' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_B) then result := result+'AnalogVideo_SECAM_B' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_D) then result := result+'AnalogVideo_SECAM_D' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_G) then result := result+'AnalogVideo_SECAM_G' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_H) then result := result+'AnalogVideo_SECAM_H' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_K) then result := result+'AnalogVideo_SECAM_K' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_K1) then result := result+'AnalogVideo_SECAM_K1' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_AnalogVideo_SECAM_L) then result := result+'AnalogVideo_SECAM_L' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG2_VIDEO) then result := result+'MPEG2_VIDEO' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG2_PROGRAM) then result := result+'MPEG2_PROGRAM' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG2_TRANSPORT) then result := result+'MPEG2_TRANSPORT' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MPEG2_AUDIO) then result := result+'MPEG2_AUDIO' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DOLBY_AC3) then result := result+'DOLBY_AC3' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVD_SUBPICTURE) then result := result+'DVD_SUBPICTURE' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVD_LPCM_AUDIO) then result := result+'DVD_LPCM_AUDIO' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DTS) then result := result+'DTS' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_SDDS) then result := result+'SDDS' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVD_NAVIGATION_PCI) then result := result+'PCI' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVD_NAVIGATION_DSI) then result := result+'DSI' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DVD_NAVIGATION_PROVIDER) then result := result+'PROVIDER' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_MP42) then result := result+'MS-MPEG4' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_DIVX) then result := result+'DIVX' else if IsEqualGUID(MediaType.subtype,MEDIASUBTYPE_VOXWARE) then result := result+'VOXWARE_MetaSound' else result := result+'UnKnown '; // format result := result+ ' Format: '; if IsEqualGUID(MediaType.formattype,FORMAT_VideoInfo) then begin result := result+'VideoInfo '; if ((MediaType.cbFormat > 0) and assigned(MediaType.pbFormat)) then with PVideoInfoHeader(MediaType.pbFormat)^.bmiHeader do result := result + format('%s %dX%d, %d bits', [GetFOURCC(biCompression), biWidth, biHeight, biBitCount]); end else begin if IsEqualGUID(MediaType.formattype,FORMAT_VideoInfo2) then begin result := result+'VideoInfo2 '; if ((MediaType.cbFormat > 0) and assigned(MediaType.pbFormat)) then with PVideoInfoHeader2(MediaType.pbFormat)^.bmiHeader do result := result + format('%s %dX%d, %d bits', [GetFOURCC(biCompression), biWidth, biHeight, biBitCount]); end else begin if IsEqualGUID(MediaType.formattype,FORMAT_WaveFormatEx) then begin result := result+'WaveFormatEx: '; if ((MediaType.cbFormat > 0) and assigned(MediaType.pbFormat)) then begin case PWaveFormatEx(MediaType.pbFormat)^.wFormatTag of $0001: result := result+'PCM'; // common $0002: result := result+'ADPCM'; $0003: result := result+'IEEE_FLOAT'; $0005: result := result+'IBM_CVSD'; $0006: result := result+'ALAW'; $0007: result := result+'MULAW'; $0010: result := result+'OKI_ADPCM'; $0011: result := result+'DVI_ADPCM'; $0012: result := result+'MEDIASPACE_ADPCM'; $0013: result := result+'SIERRA_ADPCM'; $0014: result := result+'G723_ADPCM'; $0015: result := result+'DIGISTD'; $0016: result := result+'DIGIFIX'; $0017: result := result+'DIALOGIC_OKI_ADPCM'; $0018: result := result+'MEDIAVISION_ADPCM'; $0020: result := result+'YAMAHA_ADPCM'; $0021: result := result+'SONARC'; $0022: result := result+'DSPGROUP_TRUESPEECH'; $0023: result := result+'ECHOSC1'; $0024: result := result+'AUDIOFILE_AF36'; $0025: result := result+'APTX'; $0026: result := result+'AUDIOFILE_AF10'; $0030: result := result+'DOLBY_AC2'; $0031: result := result+'GSM610'; $0032: result := result+'MSNAUDIO'; $0033: result := result+'ANTEX_ADPCME'; $0034: result := result+'CONTROL_RES_VQLPC'; $0035: result := result+'DIGIREAL'; $0036: result := result+'DIGIADPCM'; $0037: result := result+'CONTROL_RES_CR10'; $0038: result := result+'NMS_VBXADPCM'; $0039: result := result+'CS_IMAADPCM'; $003A: result := result+'ECHOSC3'; $003B: result := result+'ROCKWELL_ADPCM'; $003C: result := result+'ROCKWELL_DIGITALK'; $003D: result := result+'XEBEC'; $0040: result := result+'G721_ADPCM'; $0041: result := result+'G728_CELP'; $0050: result := result+'MPEG'; $0055: result := result+'MPEGLAYER3'; $0060: result := result+'CIRRUS'; $0061: result := result+'ESPCM'; $0062: result := result+'VOXWARE'; $0063: result := result+'CANOPUS_ATRAC'; $0064: result := result+'G726_ADPCM'; $0065: result := result+'G722_ADPCM'; $0066: result := result+'DSAT'; $0067: result := result+'DSAT_DISPLAY'; $0075: result := result+'VOXWARE'; // aditionnal ??? $0080: result := result+'SOFTSOUND'; $0100: result := result+'RHETOREX_ADPCM'; $0200: result := result+'CREATIVE_ADPCM'; $0202: result := result+'CREATIVE_FASTSPEECH8'; $0203: result := result+'CREATIVE_FASTSPEECH10'; $0220: result := result+'QUARTERDECK'; $0300: result := result+'FM_TOWNS_SND'; $0400: result := result+'BTV_DIGITAL'; $1000: result := result+'OLIGSM'; $1001: result := result+'OLIADPCM'; $1002: result := result+'OLICELP'; $1003: result := result+'OLISBC'; $1004: result := result+'OLIOPR'; $1100: result := result+'LH_CODEC'; $1400: result := result+'NORRIS'; else result := result+'Unknown'; end; with PWaveFormatEx(MediaType.pbFormat)^ do result := result + format(', %d Hertz, %d Bits, %d Channels', [nSamplesPerSec, cbSize, nChannels]); end; end else begin if IsEqualGUID(MediaType.formattype,FORMAT_MPEGVideo) then begin result := result+'MPEGVideo '; if ((MediaType.cbFormat > 0) and assigned(MediaType.pbFormat)) then with PMPEG1VIDEOINFO(MediaType.pbFormat)^.hdr.bmiHeader do result := result + format('%s %dX%d, %d bits', [GetFOURCC(biCompression), biWidth, biHeight, biBitCount]); end else begin if IsEqualGUID(MediaType.formattype,FORMAT_MPEG2Video) then begin result := result+'MPEGStreams '; if ((MediaType.cbFormat > 0) and assigned(MediaType.pbFormat)) then with PMPEG2VIDEOINFO(MediaType.pbFormat)^.hdr.bmiHeader do result := result + format('%s %dX%d, %d bits', [GetFOURCC(biCompression), biWidth, biHeight, biBitCount]); end else begin // todo if IsEqualGUID(MediaType.formattype,FORMAT_DvInfo) then result := result+'DvInfo' else if IsEqualGUID(MediaType.formattype,FORMAT_MPEGStreams) then result := result+'MPEGStreams' else if IsEqualGUID(MediaType.formattype,FORMAT_DolbyAC3) then result := result+'DolbyAC3' else if IsEqualGUID(MediaType.formattype,FORMAT_MPEG2Audio) then result := result+'MPEG2Audio' else if IsEqualGUID(MediaType.formattype,FORMAT_DVD_LPCMAudio) then result := result+'DVD_LPCMAudio' else result := result+'Unknown'; end; end; end; end; end; end; function ShowFilterPropertyPage(parent: THandle; Filter: IBaseFilter; PropertyPage: TPropertyPage = ppDefault): HRESULT; var SpecifyPropertyPages : ISpecifyPropertyPages; CaptureDialog : IAMVfwCaptureDialogs; CompressDialog: IAMVfwCompressDialogs; CAGUID :TCAGUID; FilterInfo: TFilterInfo; Code: Integer; begin result := S_FALSE; code := 0; if Filter = nil then exit; ZeroMemory(@FilterInfo, SizeOf(TFilterInfo)); case PropertyPage of ppVFWCapDisplay: code := VfwCaptureDialog_Display; ppVFWCapFormat : code := VfwCaptureDialog_Format; ppVFWCapSource : code := VfwCaptureDialog_Source; ppVFWCompConfig: code := VfwCompressDialog_Config; ppVFWCompAbout : code := VfwCompressDialog_About; end; case PropertyPage of ppDefault: begin result := Filter.QueryInterface(IID_ISpecifyPropertyPages, SpecifyPropertyPages); if result <> S_OK then exit; result := SpecifyPropertyPages.GetPages(CAGUID); if result <> S_OK then exit; result := Filter.QueryFilterInfo(FilterInfo); if result <> S_OK then exit; result := OleCreatePropertyFrame(parent, 0, 0, FilterInfo.achName, 1, @Filter, CAGUID.cElems, CAGUID.pElems, 0, 0, nil ) end; ppVFWCapDisplay..ppVFWCapSource: begin result := Filter.QueryInterface(IID_IAMVfwCaptureDialogs,CaptureDialog); if (result <> S_OK) then exit; result := CaptureDialog.HasDialog(code); if result <> S_OK then exit; result := CaptureDialog.ShowDialog(code,parent); end; ppVFWCompConfig..ppVFWCompAbout: begin result := Filter.QueryInterface(IID_IAMVfwCompressDialogs, CompressDialog); if (result <> S_OK) then exit; case PropertyPage of ppVFWCompConfig: result := CompressDialog.ShowDialog(VfwCompressDialog_QueryConfig, 0); ppVFWCompAbout : result := CompressDialog.ShowDialog(VfwCompressDialog_QueryAbout, 0); end; if result <> S_OK then exit; result := CompressDialog.ShowDialog(code,parent); end; end; end; function HaveFilterPropertyPage(Filter: IBaseFilter; PropertyPage: TPropertyPage = ppDefault): boolean; var SpecifyPropertyPages : ISpecifyPropertyPages; CaptureDialog : IAMVfwCaptureDialogs; CompressDialog: IAMVfwCompressDialogs; Code: Integer; HR: HRESULT; begin result := false; code := 0; if Filter = nil then exit; case PropertyPage of ppVFWCapDisplay: code := VfwCaptureDialog_Display; ppVFWCapFormat : code := VfwCaptureDialog_Format; ppVFWCapSource : code := VfwCaptureDialog_Source; ppVFWCompConfig: code := VfwCompressDialog_QueryConfig; ppVFWCompAbout : code := VfwCompressDialog_QueryAbout; end; case PropertyPage of ppDefault: result := Succeeded(Filter.QueryInterface(IID_ISpecifyPropertyPages, SpecifyPropertyPages)); ppVFWCapDisplay..ppVFWCapSource: begin HR := Filter.QueryInterface(IID_IAMVfwCaptureDialogs,CaptureDialog); if (HR <> S_OK) then exit; result := Succeeded(CaptureDialog.HasDialog(code)); end; ppVFWCompConfig..ppVFWCompAbout: begin HR := Filter.QueryInterface(IID_IAMVfwCompressDialogs, CompressDialog); if (HR <> S_OK) then exit; result := Succeeded(CompressDialog.ShowDialog(code,0)); end; end; end; function ShowPinPropertyPage(parent: THandle; Pin: IPin): HRESULT; var SpecifyPropertyPages: ISpecifyPropertyPages; CAGUID :TCAGUID; PinInfo: TPinInfo; begin result := S_FALSE; if Pin = nil then exit; result := Pin.QueryInterface(IID_ISpecifyPropertyPages, SpecifyPropertyPages); if result <> S_OK then exit; result := SpecifyPropertyPages.GetPages(CAGUID); if result <> S_OK then exit; result := Pin.QueryPinInfo(PinInfo); if result <> S_OK then exit; result := OleCreatePropertyFrame(parent, 0, 0, PinInfo.achName, 1, @Pin, CAGUID.cElems, CAGUID.pElems, 0, 0, nil ) end; function RefTimeToMiliSec(RefTime: int64): Cardinal; begin result := Cardinal(RefTime div 10000); end; function MiliSecToRefTime(Milisec: int64): Int64; begin result := Milisec * 10000; end; // The mechanism for describing a bitmap format is with the BITMAPINFOHEADER // This is really messy to deal with because it invariably has fields that // follow it holding bit fields, palettes and the rest. This function gives // the number of bytes required to hold a VIDEOINFO that represents it. This // count includes the prefix information (like the rcSource rectangle) the // BITMAPINFOHEADER field, and any other colour information on the end. // // WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make // sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't // right at the start of the VIDEOINFO (there are a number of other fields), // // CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); // function GetBitmapFormatSize(const Header: TBitmapInfoHeader): Integer; var Size, Entries: Integer; begin // Everyone has this to start with this Size := SIZE_PREHEADER + Header.biSize; ASSERT(Header.biSize >= sizeof(TBitmapInfoHeader)); // Does this format use a palette, if the number of colours actually used // is zero then it is set to the maximum that are allowed for that colour // depth (an example is 256 for eight bits). Truecolour formats may also // pass a palette with them in which case the used count is non zero // This would scare me. ASSERT((Header.biBitCount <= iPALETTE) or (Header.biClrUsed = 0)); if ((Header.biBitCount <= iPALETTE) or BOOL(Header.biClrUsed)) then begin Entries := DWORD(1) shl Header.biBitCount; if BOOL(Header.biClrUsed) then Entries := Header.biClrUsed; Size := Size + Entries * sizeof(RGBQUAD); end; // Truecolour formats may have a BI_BITFIELDS specifier for compression // type which means that room for three DWORDs should be allocated that // specify where in each pixel the RGB colour components may be found if (Header.biCompression = BI_BITFIELDS) then Size := Size + SIZE_MASKS; result := Size; end; function GetSourceRectFromMediaType(const MediaType: TAMMediaType): TRect; function GetbmiHeader(const MediaType: TAMMediaType): PBitmapInfoHeader; begin result := nil; if MediaType.pbFormat = nil then exit; if (IsEqualGUID(MediaType.formattype, FORMAT_VideoInfo) and (MediaType.cbFormat >= sizeof(TVIDEOINFOHEADER))) then result := @PVIDEOINFOHEADER(MediaType.pbFormat)^.bmiHeader else if (IsEqualGUID(MediaType.formattype, FORMAT_VideoInfo2) and (MediaType.cbFormat >= sizeof(TVIDEOINFOHEADER2))) then result := @PVIDEOINFOHEADER2(MediaType.pbFormat)^.bmiHeader; end; var bih: PBITMAPINFOHEADER; begin ZeroMemory(@Result,SizeOf(TRect)); if MediaType.pbFormat = nil then exit; if (IsEqualGUID(MediaType.formattype, FORMAT_VideoInfo) and (MediaType.cbFormat >= sizeof(TVIDEOINFOHEADER))) then result := PVideoInfoHeader(MediaType.pbFormat)^.rcSource else if (IsEqualGUID(MediaType.formattype, FORMAT_VideoInfo2) and (MediaType.cbFormat >= sizeof(TVIDEOINFOHEADER2))) then result := PVIDEOINFOHEADER2(MediaType.pbFormat)^.rcSource; if IsRectEmpty(result) then begin bih := GetbmiHeader(MediaType); if bih <> nil then SetRect(result, 0, 0, abs(bih.biWidth), abs(bih.biHeight)); end; end; function StretchRect(R, IR: TRect): TRect; var iW, iH: Integer; rW, rH: Integer; begin iW := IR.Right - IR.Left; iH := IR.Bottom - IR.Top; rW := R.Right - R.Left; rH := R.Bottom - R.Top; if (rW / iW) < (rH / iH) then begin iH := MulDiv(iH, rW, iW); iW := MulDiv(iW, rW, iW); end else begin iW := MulDiv(iW, rH, iH); iH := MulDiv(iH, rH, iH); end; SetRect(Result, 0, 0, iW, iH); OffsetRect(Result, R.Left + (rW - iW) div 2, R.Top + (rH - iH) div 2); end; function CheckDSError(HR: HRESULT): HRESULT; var Excep: EDirectShowException; begin Result := HR; if Failed(HR) then begin Excep := EDirectShowException.Create(format(GetErrorString(HR)+' ($%x).',[HR])); Excep.ErrorCode := HR; raise Excep; end; end; // ***************************************************************************** // TSysDevEnum // ***************************************************************************** procedure TSysDevEnum.GetCat(catlist: TList; CatGUID: TGUID); var SysDevEnum : ICreateDevEnum; EnumCat : IEnumMoniker; Moniker : IMoniker; Fetched : ULONG; PropBag : IPropertyBag; Name : olevariant; hr : HRESULT; i : integer; begin if catList.Count > 0 then for i := 0 to (catList.Count - 1) do if assigned(catList.Items[i]) then Dispose(catList.Items[i]); catList.Clear; CocreateInstance(CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC, IID_ICreateDevEnum, SysDevEnum); hr := SysDevEnum.CreateClassEnumerator(CatGUID, EnumCat, 0); if (hr = S_OK) then begin while(EnumCat.Next(1, Moniker, @Fetched) = S_OK) do begin Moniker.BindToStorage(nil, nil, IID_IPropertyBag, PropBag); new(ACategory); PropBag.Read('FriendlyName', Name, nil); ACategory^.FriendlyName := Name; if (PropBag.Read('CLSID',Name,nil) = S_OK) then ACategory^.CLSID := StringToGUID(Name) else ACategory^.CLSID := GUID_NULL; catlist.Add(ACategory); PropBag := nil; Moniker := nil; end; end; EnumCat :=nil; SysDevEnum :=nil; end; Constructor TSysDevEnum.Create; begin FCategories := TList.Create; FFilters := TList.Create; getcat(FCategories,CLSID_ActiveMovieCategories); end; constructor TSysDevEnum.create(guid: TGUID); begin FCategories := TList.Create; FFilters := TList.Create; getcat(FCategories,CLSID_ActiveMovieCategories); SelectGUIDCategory(guid); end; destructor TSysDevEnum.Destroy; var i: integer; begin inherited Destroy; if FCategories.Count > 0 then for i := 0 to (FCategories.Count - 1) do if assigned(FCategories.Items[i]) then Dispose(FCategories.items[i]); FCategories.Clear; FreeAndNil(FCategories); if FFilters.Count > 0 then for i := 0 to (FFilters.Count - 1) do if assigned(FFilters.Items[i]) then Dispose(FFilters.Items[i]); FFilters.Clear; FreeAndNil(FFilters); end; function TSysDevEnum.GetCategory(item: integer): TFilCatNode; var PCategory: PFilCatNode; begin PCategory := FCategories.Items[item]; result := PCategory^; end; function TSysDevEnum.GetFilter(item: integer): TFilCatNode; var PCategory: PFilCatNode; begin PCategory := FFilters.Items[item]; result := PCategory^; end; function TSysDevEnum.GetCountCategories: integer; begin result := FCategories.Count; end; function TSysDevEnum.GetCountFilters: integer; begin result := FFilters.Count; end; procedure TSysDevEnum.SelectGUIDCategory(GUID: TGUID); begin FGUID := GUID; getcat(FFilters,FGUID); end; procedure TSysDevEnum.SelectIndexCategory(index: integer); begin SelectGUIDCategory(Categories[index].CLSID); end; function TSysDevEnum.GetMoniker(index: integer): IMoniker; var SysDevEnum : ICreateDevEnum; EnumCat : IEnumMoniker; begin result := nil; if ((index < CountFilters) and (index >= 0)) then begin CocreateInstance(CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC, IID_ICreateDevEnum, SysDevEnum); SysDevEnum.CreateClassEnumerator(FGUID, EnumCat, 0); EnumCat.Skip(index); EnumCat.Next(1, Result, nil); EnumCat.Reset; SysDevEnum := nil; EnumCat := nil; end end; function TSysDevEnum.GetBaseFilter(index: integer): IBaseFilter; var SysDevEnum : ICreateDevEnum; EnumCat : IEnumMoniker; Moniker : IMoniker; begin result := nil; if ((index < CountFilters) and (index >= 0)) then begin CocreateInstance(CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC, IID_ICreateDevEnum, SysDevEnum); SysDevEnum.CreateClassEnumerator(FGUID, EnumCat, 0); EnumCat.Skip(index); EnumCat.Next(1, Moniker, nil); Moniker.BindToObject(nil, nil, IID_IBaseFilter, result); EnumCat.Reset; SysDevEnum := nil; EnumCat := nil; Moniker := nil; end end; function TSysDevEnum.GetBaseFilter(GUID: TGUID): IBaseFilter; var i: integer; begin result := nil; if countFilters > 0 then for i := 0 to CountFilters - 1 do if IsEqualGUID(GUID,Filters[i].CLSID) then begin result := GetBaseFilter(i); exit; end; end; //****************************************************************************** // // TMediaType implementation // //****************************************************************************** destructor TMediaType.Destroy; begin FreeMediaType(AMMediaType); dispose(AMMediaType); inherited Destroy; end; // copy constructor does a deep copy of the format block constructor TMediaType.Create; begin InitMediaType; end; constructor TMediaType.Create(majortype: TGUID); begin InitMediaType; AMMediaType.majortype := majortype; end; constructor TMediaType.Create(mediatype: PAMMediaType); begin InitMediaType; CopyMediaType(AMMediaType, mediatype); end; constructor TMediaType.Create(MTClass: TMediaType); begin InitMediaType; CopyMediaType(AMMediaType, MTClass.AMMediaType); end; procedure TMediaType.DefineProperties(Filer: TFiler); function DoWrite: Boolean; begin result := true; if Filer.Ancestor <> nil then begin Result := True; if Filer.Ancestor is TMediaType then Result := not Equal(TMediaType(Filer.Ancestor)) end; end; begin Filer.DefineBinaryProperty('data', ReadData, WriteData, DoWrite); end; procedure TMediaType.ReadData(Stream: TStream); begin ResetFormatBuffer; Stream.Read(AMMediaType^, SizeOf(TAMMediaType)); if FormatLength > 0 then begin AMMediaType.pbFormat := CoTaskMemAlloc(FormatLength); Stream.Read(AMMediaType.pbFormat^, FormatLength) end; end; procedure TMediaType.WriteData(Stream: TStream); begin Stream.Write(AMMediaType^, SizeOf(TAMMediaType)); if FormatLength > 0 then Stream.Write(AMMediaType.pbFormat^, FormatLength); end; // copy MTClass.AMMediaType to current AMMediaType procedure TMediaType.Assign(Source: TPersistent); begin if Source is TMediaType then begin if (Source <> self) then begin FreeMediaType(AMMediaType); CopyMediaType(AMMediaType, TMediaType(Source).AMMediaType); end; end else inherited Assign(Source); end; // this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate // the following assignment operator itself, however it could introduce some // memory conflicts and leaks in the process because the structure contains // a dynamically allocated block (pbFormat) which it will not copy correctly procedure TMediaType.Read(mediatype: PAMMediaType); begin if (mediatype <> self.AMMediaType) then begin FreeMediaType(AMMediaType); CopyMediaType(AMMediaType, mediatype); end; end; function TMediaType.Equal(MTClass: TMediaType): boolean; begin // I don't believe we need to check sample size or // temporal compression flags, since I think these must // be represented in the type, subtype and format somehow. They // are pulled out as separate flags so that people who don't understand // the particular format representation can still see them, but // they should duplicate information in the format block. result := ((IsEqualGUID(AMMediaType.majortype,MTClass.AMMediaType.majortype) = TRUE) and (IsEqualGUID(AMMediaType.subtype,MTClass.AMMediaType.subtype) = TRUE) and (IsEqualGUID(AMMediaType.formattype,MTClass.AMMediaType.formattype) = TRUE) and (AMMediaType.cbFormat = MTClass.AMMediaType.cbFormat) and ( (AMMediaType.cbFormat = 0) or (CompareMem(AMMediaType.pbFormat, MTClass.AMMediaType.pbFormat, AMMediaType.cbFormat)))); end; // Check to see if they are equal function TMediaType.NotEqual(MTClass: TMediaType): boolean; begin if (self = MTClass) then result := FALSE else result := TRUE; end; // By default, TDSMediaType objects are initialized with a major type of GUID_NULL. // Call this method to determine whether the object has been correctly initialized. function TMediaType.IsValid: boolean; begin result := not IsEqualGUID(AMMediaType.majortype,GUID_NULL); end; // Determines if the samples have a fixed size or a variable size. function TMediaType.IsFixedSize: boolean; begin result := AMMediaType.bFixedSizeSamples; end; // Determines if the stream uses temporal compression. function TMediaType.IsTemporalCompressed: boolean; begin result := AMMediaType.bTemporalCompression; end; // If the sample size is fixed, returns the sample size in bytes. Otherwise, // returns zero. function TMediaType.GetSampleSize: ULONG; begin if IsFixedSize then result := AMMediaType.lSampleSize else result := 0; end; // If value of sz is zero, the media type uses variable sample sizes. Otherwise, // the sample size is fixed at sz bytes. procedure TMediaType.SetSampleSize(SZ: ULONG); begin if (sz = 0) then begin SetVariableSize; end else begin AMMediaType.bFixedSizeSamples := TRUE; AMMediaType.lSampleSize := sz; end; end; // Specifies that samples do not have a fixed size. procedure TMediaType.SetVariableSize; begin AMMediaType.bFixedSizeSamples := FALSE; end; // Specifies whether samples are compressed using temporal compression procedure TMediaType.SetTemporalCompression(bCompressed: boolean); begin AMMediaType.bTemporalCompression := bCompressed; end; // Retrieves a pointer to the format block. function TMediaType.Format: pointer; begin result := AMMediaType.pbFormat; end; //Retrieves the length of the format block. function TMediaType.FormatLength: ULONG; begin result := AMMediaType.cbFormat; end; function TMediaType.SetFormat(pFormat: pointer; length: ULONG): boolean; begin if (nil = AllocFormatBuffer(length)) then begin result := false; exit; end; ASSERT(AMMediatype.pbFormat<>nil); CopyMemory(AMMediatype.pbFormat,pFormat,length); result := true; end; // reset the format buffer procedure TMediaType.ResetFormatBuffer; begin if (AMMediaType.cbFormat <> 0) then CoTaskMemFree(AMMediaType.pbFormat); AMMediaType.cbFormat := 0; AMMediaType.pbFormat := nil; end; // allocate length bytes for the format and return a read/write pointer // If we cannot allocate the new block of memory we return NULL leaving // the original block of memory untouched (as does ReallocFormatBuffer) function TMediaType.AllocFormatBuffer(length: ULONG): pointer; var pNewFormat : pointer; begin ASSERT(length<>0); // do the types have the same buffer size if (AMMediaType.cbFormat = length) then begin result := AMMediaType.pbFormat; exit; end; // allocate the new format buffer pNewFormat := CoTaskMemAlloc(length); if (pNewFormat = nil) then begin if (length <= AMMediaType.cbFormat) then begin result := AMMediatype.pbFormat; //reuse the old block anyway. exit; end else begin result := nil; exit; end; end; // delete the old format if (AMMediaType.cbFormat <> 0) then begin ASSERT(AMMediaType.pbFormat<>nil); CoTaskMemFree(AMMediaType.pbFormat); end; AMMediaType.cbFormat := length; AMMediaType.pbFormat := pNewFormat; result := AMMediaType.pbFormat; end; // reallocate length bytes for the format and return a read/write pointer // to it. We keep as much information as we can given the new buffer size // if this fails the original format buffer is left untouched. The caller // is responsible for ensuring the size of memory required is non zero function TMediaType.ReallocFormatBuffer(length: ULONG): pointer; var pNewFormat: pointer; begin ASSERT(length<>0); // do the types have the same buffer size if (AMMediaType.cbFormat = length) then begin result := AMMediaType.pbFormat; exit; end; // allocate the new format buffer pNewFormat := CoTaskMemAlloc(length); if (pNewFormat = nil) then begin if (length <= AMMediaType.cbFormat) then begin result := AMMediaType.pbFormat; //reuse the old block anyway. exit; end else begin result := nil; exit; end; end; // copy any previous format (or part of if new is smaller) // delete the old format and replace with the new one if (AMMediaType.cbFormat <> 0) then begin ASSERT(AMMediaType.pbFormat<>nil); CopyMemory(pNewFormat, AMMediaType.pbFormat, min(length,AMMediaType.cbFormat)); CoTaskMemFree(AMMediaType.pbFormat); end; AMMediaType.cbFormat := length; AMMediaType.pbFormat := pNewFormat; result := pNewFormat; end; // initialise a media type structure procedure TMediaType.InitMediaType; begin new(AMMediaType); ZeroMemory(AMMediaType, sizeof(TAMMediaType)); AMMediaType.lSampleSize := 1; AMMediaType.bFixedSizeSamples := TRUE; end; //Determines if this media type matches a partially specified media type. function TMediaType.MatchesPartial(ppartial: TMediaType): boolean; begin if (not IsEqualGUID(ppartial.AMMediaType.majortype, GUID_NULL) and not IsEqualGUID(AMMediaType.majortype, ppartial.AMMediaType.majortype)) then begin result := false; exit; end; if (not IsEqualGUID(ppartial.AMMediaType.subtype, GUID_NULL) and not IsEqualGUID(AMMediaType.subtype, ppartial.AMMediaType.subtype)) then begin result := false; exit; end; if not IsEqualGUID(ppartial.AMMediaType.formattype, GUID_NULL) then begin // if the format block is specified then it must match exactly if not IsEqualGUID(AMMediaType.formattype, ppartial.AMMediaType.formattype) then begin result := FALSE; exit; end; if (AMMediaType.cbFormat <> ppartial.AMMediaType.cbFormat) then begin result := FALSE; exit; end; if ((AMMediaType.cbFormat <> 0) and (CompareMem(AMMediaType.pbFormat, ppartial.AMMediaType.pbFormat, AMMediaType.cbFormat) <> false)) then begin result := FALSE; exit; end; end; result := TRUE; end; // a partially specified media type can be passed to IPin::Connect // as a constraint on the media type used in the connection. // the type, subtype or format type can be null. function TMediaType.IsPartiallySpecified: boolean; begin if (IsEqualGUID(AMMediaType.majortype, GUID_NULL) or IsEqualGUID(AMMediaType.formattype, GUID_NULL)) then begin result := TRUE; exit; end else begin result := FALSE; exit; end; end; function TMediaType.GetMajorType: TGUID; begin result := AMMediaType.majortype; end; procedure TMediaType.SetMajorType(MT: TGUID); begin AMMediaType.majortype := MT; end; function TMediaType.GetSubType: TGUID; begin result := AMMediaType.subtype; end; procedure TMediaType.SetSubType(ST: TGUID); begin AMMediaType.subtype := ST; end; // set the type of the media type format block, this type defines what you // will actually find in the format pointer. For example FORMAT_VideoInfo or // FORMAT_WaveFormatEx. In the future this may be an interface pointer to a // property set. Before sending out media types this should be filled in. procedure TMediaType.SetFormatType(const GUID: TGUID); begin AMMediaType.formattype := GUID; end; function TMediaType.GetFormatType: TGUID; begin result := AMMediaType.formattype; end; //****************************************************************************** // // TDSEnumMediaType Implementation // //****************************************************************************** constructor TEnumMediaType.Create; begin FList := TList.Create; end; constructor TEnumMediaType.Create(Pin: IPin); var EnumMT : IEnumMediaTypes; hr : HRESULT; begin FList := TList.Create; assert(pin <> nil,'IPin not assigned'); hr := pin.EnumMediaTypes(EnumMT); if (hr <> S_OK) then exit; Create(ENumMT); end; constructor TEnumMediaType.Create(EnumMT: IEnumMediaTypes); var pmt: PAMMediaType; begin if (FList = nil) then FList := TList.Create; assert(EnumMT <> nil,'IEnumMediaType not assigned'); while (EnumMT.Next(1,pmt,nil)= S_OK) do begin FList.Add(TMediaType.Create(pmt)); end; end; constructor TEnumMediaType.Create(FileName: TFileName); begin FList := TList.Create; Assign(FileName); end; destructor TEnumMediaType.Destroy; begin Clear; FList.Free; end; procedure TEnumMediaType.Assign(Pin: IPin); var EnumMT : IEnumMediaTypes; hr : HRESULT; begin Clear; assert(pin <> nil,'IPin not assigned'); hr := pin.EnumMediaTypes(EnumMT); if (hr <> S_OK) then exit; Assign(ENumMT); end; procedure TEnumMediaType.Assign(EnumMT: IEnumMediaTypes); var pmt: PAMMediaType; begin if (count <> 0) then Clear; assert(EnumMT <> nil,'IEnumMediaType not assigned'); while (EnumMT.Next(1,pmt,nil)= S_OK) do begin FList.Add(TMediaType.Create(pmt)); end; end; procedure TEnumMediaType.Assign(FileName: TFileName); var MediaDet: IMediaDet; KeyProvider : IServiceProvider; hr: HRESULT; Streams: LongInt; i: longint; MediaType: TAMMediaType; begin Clear; hr := CoCreateInstance(CLSID_MediaDet, nil, CLSCTX_INPROC, IID_IMediaDet, MediaDet); assert(hr = S_OK, 'Media Detector not available'); hr := MediaDet.put_Filename(FileName); if hr <> S_OK then begin MediaDet := nil; Exit; end; MediaDet.get_OutputStreams(Streams); if streams > 0 then begin for i := 0 to (streams - 1) do begin MediaDet.put_CurrentStream(i); MediaDet.get_StreamMediaType(MediaType); FList.Add(TMediaType.Create(@MediaType)); end; end; KeyProvider := nil; MediaDet := nil; end; function TEnumMediaType.GetItem(Index: Integer): TMediaType; begin result := TMediaType(Flist.Items[index]); end; function TEnumMediaType.GetMediaDescription(Index: Integer): string; begin result := ''; if ((index < count) and (index > -1)) then result := GetMediaTypeDescription(TMediaType(Flist.Items[index]).AMMediaType^); end; procedure TEnumMediaType.SetItem(Index: Integer; Item: TMediaType); begin TMediaType(Flist.Items[index]).Assign(item); end; function TEnumMediaType.GetCount: integer; begin assert(FList<>nil,'TDSEnumMediaType not created'); if (FList <> nil) then result := FList.Count else result := 0; end; function TEnumMediaType.Add(Item: TMediaType): Integer; begin result := FList.Add(Item); end; procedure TEnumMediaType.Clear; var i: Integer; begin if count <> 0 then for i := 0 to (count -1) do begin if (FList.Items[i]<>nil) then TMediaType(FList.Items[i]).Free; end; FList.Clear; end; procedure TEnumMediaType.Delete(Index: Integer); begin if (FList.Items[index]<>nil) then TMediaType(FList.Items[index]).Free; FList.Delete(index); end; // ***************************************************************************** // TDSFilterList implementation // ***************************************************************************** constructor TFilterList.Create(FilterGraph: IFilterGraph); begin inherited Create; Graph := FilterGraph; Update; end; destructor TFilterList.Destroy; begin inherited Destroy; end; procedure TFilterList.Update; var EnumFilters: IEnumFilters; Filter: IBaseFilter; begin if assigned(Graph) then Graph.EnumFilters(EnumFilters); while (EnumFilters.Next(1, Filter, nil) = S_OK) do add(Filter); EnumFilters := nil; end; procedure TFilterList.Assign(FilterGraph: IFilterGraph); begin Clear; Graph := FilterGraph; Update; end; function TFilterList.GetFilter(Index: Integer): IBaseFilter; begin result := get(index) as IBaseFilter; end; procedure TFilterList.PutFilter(Index: Integer; Item: IBaseFilter); begin put(index,Item); end; function TFilterList.First: IBaseFilter; begin result := GetFilter(0); end; function TFilterList.IndexOf(Item: IBaseFilter): Integer; begin result := inherited IndexOf(Item); end; function TFilterList.Add(Item: IBaseFilter): Integer; begin result := inherited Add(Item); end; procedure TFilterList.Insert(Index: Integer; Item: IBaseFilter); begin inherited Insert(index,item); end; function TFilterList.Last: IBaseFilter; begin result := inherited Last as IBaseFilter; end; function TFilterList.Remove(Item: IBaseFilter): Integer; begin result := inherited Remove(Item); end; function TFilterList.GetFilterInfo(index: integer): TFilterInfo; begin if assigned(items[index]) then items[index].QueryFilterInfo(result); end; // ***************************************************************************** // TPinList // ***************************************************************************** constructor TPinList.Create(BaseFilter: IBaseFilter); begin inherited Create; Filter := BaseFilter; Update; end; destructor TPinList.Destroy; begin Filter := nil; inherited Destroy; end; procedure TPinList.Update; var EnumPins : IEnumPins; Pin : IPin; begin clear; if assigned(Filter) then Filter.EnumPins(EnumPins) else exit; while (EnumPins.Next(1, pin, nil) = S_OK) do add(Pin); EnumPins := nil; end; procedure TPinList.Assign(BaseFilter: IBaseFilter); begin Clear; Filter := BaseFilter; if Filter <> nil then Update; end; function TPinList.GetConnected(Index: Integer): boolean; var Pin: IPin; begin Items[Index].ConnectedTo(Pin); Result := (Pin <> nil); end; function TPinList.GetPin(Index: Integer): IPin; begin result := get(index) as IPin; end; procedure TPinList.PutPin(Index: Integer; Item: IPin); begin put(index,Item); end; function TPinList.First: IPin; begin result := GetPin(0); end; function TPinList.IndexOf(Item: IPin): Integer; begin result := inherited IndexOf(Item); end; function TPinList.Add(Item: IPin): Integer; begin result := inherited Add(Item); end; procedure TPinList.Insert(Index: Integer; Item: IPin); begin inherited Insert(index,item); end; function TPinList.Last: IPin; begin result := inherited Last as IPin; end; function TPinList.Remove(Item: IPin): Integer; begin result := inherited Remove(Item); end; function TPinList.GetPinInfo(index: integer): TPinInfo; begin if assigned(Items[index]) then Items[index].QueryPinInfo(result); end; // ***************************************************************************** // TPersistentMemory // ***************************************************************************** constructor TPersistentMemory.Create; begin FData := nil; FDataLength := 0; end; destructor TPersistentMemory.Destroy; begin AllocateMemory(0); inherited destroy; end; procedure TPersistentMemory.AllocateMemory(ALength: Cardinal); begin if (FDataLength > 0) and (FData <> nil) then begin FreeMem(FData, FDataLength); FData := nil; FDataLength := 0; end; if ALength > 0 then begin GetMem(FData, ALength); ZeroMemory(FData, ALength); FDataLength := ALength; end end; procedure TPersistentMemory.ReadData(Stream: TStream); var ALength: Cardinal; begin Stream.Read(ALength, SizeOf(Cardinal)); AllocateMemory(ALength); if ALength > 0 then Stream.Read(FData^, ALength); end; procedure TPersistentMemory.WriteData(Stream: TStream); begin Stream.Write(FDataLength, SizeOf(Cardinal)); if FDataLength > 0 then Stream.Write(FData^, FDataLength); end; procedure TPersistentMemory.Assign(Source: TPersistent); begin if Source is TPersistentMemory then begin if (Source <> self) then begin AllocateMemory(TPersistentMemory(Source).FDataLength); if FDataLength > 0 then move(TPersistentMemory(Source).FData^, FData^, FDataLength); end; end else inherited Assign(Source); end; procedure TPersistentMemory.AssignTo(Dest: TPersistent); begin Dest.Assign(self); end; function TPersistentMemory.Equal(Memory: TPersistentMemory): boolean; begin result := false; if (Memory.FDataLength > 0) and (Memory.FDataLength = FDataLength) and (Memory.FData <> nil) and (FData <> nil) then result := comparemem(Memory.FData, FData, FDataLength); end; procedure TPersistentMemory.DefineProperties(Filer: TFiler); function DoWrite: Boolean; begin result := true; if Filer.Ancestor <> nil then begin Result := True; if Filer.Ancestor is TPersistentMemory then Result := not Equal(TPersistentMemory(Filer.Ancestor)) end; end; begin Filer.DefineBinaryProperty('data', ReadData, WriteData, DoWrite); end; // ***************************************************************************** // TBaseFilter // ***************************************************************************** procedure TBaseFilter.SetMoniker(Moniker: IMoniker); var MemStream : TMemoryStream; AdaStream : TStreamAdapter; begin if Moniker = nil then begin DataLength := 0; exit; end; MemStream := TMemoryStream.Create; AdaStream := TStreamAdapter.Create(MemStream, soReference); OleSaveToStream(Moniker, AdaStream); DataLength := MemStream.Size; move(MemStream.Memory^, Data^, DataLength); AdaStream.Free; MemStream.Free; end; function TBaseFilter.GetMoniker: IMoniker; var MemStream : TMemoryStream; AdaStream : TStreamAdapter; begin if DataLength > 0 then begin MemStream := TMemoryStream.Create; MemStream.SetSize(DataLength); move(Data^, MemStream.Memory^, DataLength); AdaStream := TStreamAdapter.Create(MemStream, soReference); OleLoadFromStream(AdaStream, IMoniker, result); AdaStream.Free; MemStream.Free; end else result := nil; end; function TBaseFilter.CreateFilter: IBaseFilter; var AMoniker : IMoniker; begin AMoniker := Moniker; if AMoniker <> nil then begin AMoniker.BindToObject(nil, nil, IBaseFilter, result); AMoniker := nil; end else result := nil; end; function TBaseFilter.PropertyBag(Name: WideString): OleVariant; var AMoniker : IMoniker; PropBag : IPropertyBag; begin AMoniker := Moniker; if AMoniker <> nil then begin AMoniker.BindToStorage(nil, nil, IID_IPropertyBag, PropBag); if PropBag <> nil then PropBag.Read(PWideChar(Name), result, nil); PropBag := nil; AMoniker := nil; end else result := NULL; end; end.